package cn.rmshadows.joffice;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;

import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.TargetDataLine;

/**
 * https://www.codejava.net/coding/a-utility-for-recording-sound-in-java
 * 
 * @author codejava.net
 */
public class RecordingUtil {
	private static final int BUFFER_SIZE = 4096;
	private ByteArrayOutputStream recordBytes;
	private TargetDataLine audioLine;
	private AudioFormat format;
	private Mixer.Info mixer;

	private boolean isRunning;

	public RecordingUtil(AudioFormat af, Mixer.Info m) {
		setAudioFormat(af);
		setMixerInfo(m);
	}

	private void setMixerInfo(Mixer.Info m) {
		mixer = m;
	}

	/**
	 * Defines a default audio format used to record
	 */
	private void setAudioFormat(AudioFormat af) {
		format = af;
	}

	/**
	 * Start recording sound.
	 * 
	 * @throws LineUnavailableException if the system does not support the specified
	 *                                  audio format nor open the audio data line.
	 */
	public void start() throws LineUnavailableException {
		DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
		// checks if system supports the data line
		if (!AudioSystem.isLineSupported(info)) {
			throw new LineUnavailableException("The system does not support the specified format.");
		}

//		audioLine = AudioSystem.getTargetDataLine(format);
		audioLine = (TargetDataLine) AudioSystem.getMixer(mixer).getLine(info);

		audioLine.open(format);
		audioLine.start();

		byte[] buffer = new byte[BUFFER_SIZE];
		int bytesRead = 0;

		recordBytes = new ByteArrayOutputStream();
		isRunning = true;
		new Thread(new Runnable() {
			@Override
			public void run() {
				while (isRunning) {
					try {
						Thread.sleep(5000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					if (buffer[0] == 0) {
						System.out.println("No Voice ...？");
					}else {
						System.out.println("Recording...");
					}
				}
				System.out.println("Record has been stoped.");
			}
		}).start();
		while (isRunning) {
			bytesRead = audioLine.read(buffer, 0, buffer.length);
//			System.out.print(buffer[0]);
			recordBytes.write(buffer, 0, bytesRead);
		}
	}

	/**
	 * Stop recording sound.
	 * 
	 * @throws IOException if any I/O error occurs.
	 */
	public void stop() throws IOException {
		isRunning = false;

		if (audioLine != null) {
			audioLine.drain();
			audioLine.close();
		}
	}

	/**
	 * Save recorded sound data into a .wav file format.
	 * 
	 * @param wavFile The file to be saved.
	 * @throws IOException if any I/O error occurs.
	 */
	public void save(File wavFile) throws IOException {
		try {
			byte[] audioData = recordBytes.toByteArray();
			ByteArrayInputStream bais = new ByteArrayInputStream(audioData);
			AudioInputStream audioInputStream = new AudioInputStream(bais, format,
					audioData.length / format.getFrameSize());

			AudioSystem.write(audioInputStream, AudioFileFormat.Type.WAVE, wavFile);

			audioInputStream.close();
			recordBytes.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}
